package aaa

import (
	"errors"
	"fmt"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"sync"

	"gitee.com/mad-wud/lin"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
)

var ws链接设置 = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
	ReadBufferSize:  1024,  //读取最大长度
	WriteBufferSize: 20480, //发送最大长度
}

func Q启动后端服务器(等待 *chan int) {
	服务端 := gin.Default()
	// 数据服务入口
	服务端.POST("/linask", func(ctx *gin.Context) {
		body, _ := ctx.GetRawData()
		var 表 lin.J键值表
		表.ZR载入(body)
		方法名 := 表.QW取文本("方法名")
		参数列表 := 表.QL取列表("参数")
		fmt.Println("表", 表.D到JSON())
		fmt.Println(方法名)
		fmt.Println(参数列表.D到JSON())
		ctx.String(200, 路由_基础(方法名, 参数列表, ctx))
	})
	// 数据下载入口
	服务端.POST("/linfile", func(ctx *gin.Context) {
		ctx.Writer.Header().Set("Access-Control-Allow-Origin", "*")
		ctx.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
		body, _ := ctx.GetRawData()
		var 表 lin.J键值表
		表.ZR载入(body)
		方法名 := 表.QW取文本("方法名")
		参数列表 := 表.QL取列表("参数")
		响应文件路径, err := 路由_文件(方法名, 参数列表, ctx)
		if err != nil {
			ctx.Header("isok", url.QueryEscape(err.Error()))
			ctx.JSON(200, gin.H{
				"msg": err.Error(),
			})
			return
		}
		if 响应文件路径 == "" {
			ctx.Header("isok", url.QueryEscape("接口未获取文件路径"))
			ctx.JSON(200, gin.H{
				"msg": "接口未获取文件路径",
			})
			return
		}

		文件信息, 错误 := os.Stat(响应文件路径)
		fmt.Println(错误, 文件信息)
		if 错误 != nil {
			ctx.Header("isok", url.QueryEscape(错误.Error()))
			ctx.JSON(200, gin.H{
				"msg": 错误.Error(),
			})
			return
		}
		ctx.Header("Content-Description", "File Transfer")
		ctx.Header("Content-Type", "application/octet-stream")
		ctx.Header("fileName", url.QueryEscape(文件信息.Name()))
		ctx.Header("isok", "ok")
		ctx.Header("msg", url.QueryEscape("下载成功_"+文件信息.Name()))
		// 数据, _ := 全_文件.D读入_文件(响应文件路径)
		// ctx.Data(200, "application/octet-stream", 数据)
		ctx.File(响应文件路径)
	})

	// 数据字节集入口
	服务端.POST("/linbytes", func(ctx *gin.Context) {
		ctx.Writer.Header().Set("Access-Control-Allow-Origin", "*")
		ctx.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
		body, _ := ctx.GetRawData()
		var 表 lin.J键值表
		表.ZR载入(body)
		方法名 := 表.QW取文本("方法名")
		参数列表 := 表.QL取列表("参数")
		字节集数据, err := 路由_字节集(方法名, 参数列表, ctx)
		if err != nil {
			ctx.Header("isok", url.QueryEscape(err.Error()))
			ctx.JSON(200, gin.H{
				"msg": err.Error(),
			})
			return
		}
		ctx.Header("isok", "ok")
		ctx.Data(200, "application/octet-stream", 字节集数据)
	})

	//ws服务升级
	服务端.GET("/ws", func(ctx *gin.Context) {
		处理ws链接(ctx)
	})

	var 基础端口 = 2024
	Q_后端服务器端口 = 0
	for i := 0; i < 30000; i++ {
		监听, err := net.Listen("tcp", ":"+F_类型.D到文本(基础端口))
		if err == nil {
			err := 监听.Close()
			if err == nil {
				Q_后端服务器端口 = 基础端口
				break
			}

		}

		基础端口++
	}
	fmt.Println("全_后端服务器端口", Q_后端服务器端口)
	if Q_后端服务器端口 == 0 {
		err := errors.New("无可用端口")
		log.Fatal(err)
	}
	var 后端配置表 lin.J键值表
	后端配置表.ZZ置整数(Q_后端服务器端口, "端口")
	后端配置表.B保存_到文件(F_文件.QX取运行目录() + "/后端配置.json")
	后端配置表.B保存_到文件(F_文件.QX取运行目录() + "/界面开发环境/后端配置.json")

	*等待 <- 1
	服务端.Run(F_文本.C创建文本(":{1}", Q_后端服务器端口))
}

func 处理ws链接(ctx *gin.Context) {
	链接, err := ws链接设置.Upgrade(ctx.Writer, ctx.Request, nil)
	if err != nil {
		fmt.Println("ws链接错误")
		return
	}
	var 记录方法名 = ""
	var 记录标识 = ""
	defer func() {
		if 记录方法名 != "" {
			if 记录标识 != "" {
				Ws标识.S删链接(记录方法名, 记录标识, 链接)
			} else {
				Ws广播.S删链接(记录方法名, 链接)
			}
		}
		fmt.Println("ws离开-->", 记录方法名)

	}()
	for {
		_, 数据, err := 链接.ReadMessage()
		if err != nil {
			fmt.Println(err)
			break
		}
		if 记录方法名 == "" {
			var 表 lin.J键值表
			表.ZR载入(数据)
			方法名 := 表.QW取文本("方法名")
			标识 := 表.QW取文本("标识")
			if 方法名 != "" {
				记录方法名 = 方法名
				if 标识 != "" {
					记录标识 = 标识
					Ws标识.Z增加链接(方法名, 标识, 链接)
				} else {
					Ws广播.Z增加链接(方法名, 链接)
					fmt.Println(Ws广播.链接表列)
				}
			}

		}
	}

}

type X响应 struct {
	方法列表 map[string]func(参数列表 lin.L列表) string
	读写许可 *sync.RWMutex
}

func (类 *X响应) C初始化() {
	类.方法列表 = make(map[string]func(参数列表 lin.L列表) string)
	var 锁 sync.RWMutex
	类.读写许可 = &锁
}

func (类 *X响应) T添加方法(方法名 string, 方法 func(参数列表 lin.L列表) string) {
	类.读写许可.Lock()
	defer 类.读写许可.Unlock()
	类.方法列表[方法名] = 方法
}

func (类 *X响应) X响应(方法名 string, 参数列表 lin.L列表) string {
	类.读写许可.RLock()
	defer 类.读写许可.RUnlock()
	if 方法, ok := 类.方法列表[方法名]; ok {
		return 方法(参数列表)
	}
	return "未绑定方法"

}

// Cors 跨域中间件
func Cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		method := c.Request.Method
		origin := c.Request.Header.Get("Origin")

		if origin != "" {
			c.Header("Access-Control-Allow-Origin", origin)
			c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
			c.Header("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, Authorization, X-CSRF-Token")
			c.Header("Access-Control-Allow-Credentials", "true")
		}

		if method == "OPTIONS" {
			c.AbortWithStatus(200)
		}

		c.Next()
	}
}
